package algorithms;

import datamanagers.ProfileMappa;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;

import datamanagers.DataManagerException;
import datamanagers.DataManagerMySql;
import org.apache.commons.lang.time.StopWatch;

import commons.SimilarityItem;

/**
 * 
 * @author Camillo Camera
 * 
 */
public class SimilarityCSM extends SimilarityAlgorithm {
	private static StopWatch sw = new StopWatch();
	private ProfileMappa mappaUser;

	/**
	 * Carica in memoria tutti i rating
	 */
	public SimilarityCSM() {
		// String fileName =
		// "/Users/raffaele/Documents/workspace_java/sii-prova2013/training.dat";
		File current_dir = new File("test.dat");
		String fileName = current_dir.getAbsolutePath().toString()
				+ System.getProperty("file.separator") + "test.dat";

		if (System.getProperty("file.separator").equals("\\"))
			fileName = fileName.replace("\\", "\\\\");
		mappaUser = new ProfileMappa();
		sw.start();

		LineIterator it;
		try {

			it = FileUtils.lineIterator(current_dir, "UTF-8");
			int count =0;
			while (it.hasNext()&& count<1000) {
				String line = it.nextLine();
				// System.out.println(line);
				Integer UserId;
				Integer ProfileId;
				Float Rating;
				String delimiter = ",";
				String[] temp = line.split(delimiter);
				UserId = Integer.valueOf(temp[0]);
				ProfileId = Integer.valueOf(temp[1]);
				Rating = Float.valueOf(temp[2]);
				
				System.out.println("UserID: " + UserId + " ProfileId: "
						+ ProfileId + " Rating: " + Rating);
				mappaUser.addMappaValori(UserId, ProfileId, Rating);
				count++;
			}
			it.close();
			System.out.println("fatto! (" + sw.getTime() + " ms)");
			sw.reset();

			System.out.println("Caricamento Mappa avvenuto con successo.. :)");

		} catch (IOException e) {

			e.printStackTrace();
		} finally {

		}

	}
/**
 * elabora la similarita
 */
	@Override
	public SimilarityItem eval(int UserId1, int UserId2) throws DataManagerException {
		HashMap<Integer, Float> scoresp1;
		HashMap<Integer, Float> scoresp2;
		scoresp1 = mappaUser.getVotazioneUserId(UserId1);
		scoresp2 = mappaUser.getVotazioneUserId(UserId2);
		SimilarityItem similarity = new SimilarityItem();
		similarity.id1 = UserId1;
		similarity.id2 =UserId2;
		// int mean_ratingu1 = scoresp1.size();
		// int mean_ratingu2 = scoresp2.size();
		double den, num_sum1, num_sum2;
		int i = 0;
		System.out.println("Calcolo l'intersezione");

		HashMap<Integer, Float[]> commonratings = intersect(scoresp1, scoresp2);

		den = 0;
		num_sum1 = 0;
		num_sum2 = 0;
		if (commonratings != null) {
			DataManagerMySql dmsql = new DataManagerMySql();
			HashMap<Integer, Float> mappaMedia = dmsql.getMappaMediaUser();

			float mediaUs1 = mappaMedia.get(UserId1);
			float mediaUs2 = mappaMedia.get(UserId2);
			int common_ratings_size = 0;
			common_ratings_size = commonratings.size();
			System.out.println("Calcolo i valori");
			if (common_ratings_size != 0) {
				for (Integer valore : commonratings.keySet()) {
					Float[] arrayValori = commonratings.get(valore);
					Float rating1 = arrayValori[0] - mediaUs1;
					Float rating2 = arrayValori[1] - mediaUs2;

					den += rating1 * rating2;
					num_sum1 += rating1 * rating1;
					num_sum2 += rating2 * rating2;
					i++;

				}

				
					similarity.similarity = (float) (den / Math.sqrt(num_sum1 * num_sum2));
					similarity.commonratings = common_ratings_size;
				

			}
		}
		return similarity;
	}

	/*
	 * private float mediaRating(HashMap<Integer, Float> mappaUs) { float valori
	 * = 0; int elementi = 0; for (Integer val : mappaUs.keySet()) { valori +=
	 * mappaUs.get(val); elementi++; } return (valori / elementi);
	 * 
	 * }
	 */
	/**
	 * Intersezione tra MappeHashMap<Integer, Float[]> la funzione scorre sempre
	 * la mappa piu corta
	 * 
	 * @param mappaUs1
	 * @param mappaUs2
	 * @return HashMap<Integer, Float[]> Float[1] valore dell'user1 , Float[2]
	 *         valore dell'user2
	 */
	public HashMap<Integer, Float[]> intersect(
			HashMap<Integer, Float> mappaUs1, HashMap<Integer, Float> mappaUs2) {
		HashMap<Integer, Float[]> intersection = null;
		int sizeMappa1 = 0;
		int sizeMappa2 = 0;
		sizeMappa1 = mappaUs1.size();
		sizeMappa2 = mappaUs2.size();
		if ((sizeMappa1 > 0) && (sizeMappa2 > 0)) {
			intersection = new HashMap<Integer, Float[]>();

			// scorro sempre sulla mappa piu piccola

			if (sizeMappa1 < sizeMappa2) {

				for (Integer userId : mappaUs1.keySet()) {
					if (mappaUs2.containsKey(userId)) {
						Float array[] = new Float[2];
						array[0] = mappaUs1.get(userId);
						array[1] = mappaUs2.get(userId);
						intersection.put(userId, array);
					}
				}
			} else {
				for (Integer userId : mappaUs2.keySet()) {
					// System.out.println("Valore chiave "+ userId +
					// "valori bool: " +valori.containsKey(userId) );

					if (mappaUs1.containsKey(userId)) {
						Float array[] = new Float[2];
						array[0] = mappaUs1.get(userId);
						array[1] = mappaUs2.get(userId);
						intersection.put(userId, array);
					}
				}
			}
		}
		return intersection;
	}
}
